package com.xinan.system.generat;


import com.jfinal.kit.StringKit;

/**
 * 用于生成代码的Columb对象.对应数据库表column
 * @author grassfox
 * @email grassfox@gmail.com
 */
public class Column implements java.io.Serializable,Cloneable{
    /**
     * Reference to the containing table
     */
    private Table _table;

    /**
     * The java.sql.Types type
     */
    private int _sqlType;

    /**
     * The sql typename. provided by JDBC driver
     */
    private String _sqlTypeName;

    /**
     * The name of the column
     */
    private String _sqlName;

    /**
     * True if the column is a primary key
     */
    private boolean _isPk;

    /**
     * @todo-javadoc Describe the column
     */
    private int _size;

    /**
     * @todo-javadoc Describe the column
     */
    private int _decimalDigits;

    /**
     * True if the column is nullable
     */
    private boolean _isNullable;

    /**
     * True if the column is indexed
     */
    private boolean _isIndexed;

    /**
     * True if the column is unique
     */
    private boolean _isUnique;

    /**
     * Null if the DB reports no default value
     */
    private String _defaultValue;

    /**
     * The comments of column
     */
    private String _remarks;

    /**
     * @param table
     * @param sqlType
     * @param sqlTypeName
     * @param sqlName
     * @param size
     * @param decimalDigits
     * @param isPk
     * @param isNullable
     * @param isIndexed
     * @param isUnique
     * @param defaultValue
     * @param remarks
     */
    public Column(Table table, int sqlType, String sqlTypeName,
                  String sqlName, int size, int decimalDigits, boolean isPk,
                  boolean isNullable, boolean isIndexed, boolean isUnique,
                  String defaultValue,String remarks) {
        if(sqlName == null) throw new NullPointerException();
        _table = table;
        _sqlType = sqlType;
        _sqlName = sqlName;
        _sqlTypeName = sqlTypeName;
        _size = size;
        _decimalDigits = decimalDigits;
        _isPk = isPk;
        _isNullable = isNullable;
        _isIndexed = isIndexed;
        _isUnique = isUnique;
        _defaultValue = defaultValue;
        _remarks = remarks;
        initOtherProperties();
    }

    public Column(Column c) {
        this(c.getTable(),
                c.getSqlType(),
                c.getSqlTypeName(),
                c.getSqlName(),
                c.getSize(),
                c.getDecimalDigits(),
                c.isPk(),
                c.isNullable(),
                c.isIndexed(),
                c.isUnique(),
                c.getDefaultValue(),
                c.getRemarks());
    }

    public Column() {
    }

    /**
     * Gets the SqlType attribute of the Column object
     *
     * @return The SqlType value
     */
    public int getSqlType() {
        return _sqlType;
    }

    /**
     * Gets the Table attribute of the DbColumn object
     *
     * @return The Table value
     */
    public Table getTable() {
        return _table;
    }

    /**
     * Gets the Size attribute of the DbColumn object
     *
     * @return The Size value
     */
    public int getSize() {
        return _size;
    }

    /**
     * Gets the DecimalDigits attribute of the DbColumn object
     *
     * @return The DecimalDigits value
     */
    public int getDecimalDigits() {
        return _decimalDigits;
    }

    /**
     * Gets the SqlTypeName attribute of the Column object
     *
     * @return The SqlTypeName value
     */
    public String getSqlTypeName() {
        return _sqlTypeName;
    }

    /**
     * Gets the SqlName attribute of the Column object
     *
     * @return The SqlName value
     */
    public String getSqlName() {
        if(_sqlName == null) throw new NullPointerException();
        return _sqlName;
    }


    /**
     * Gets the Pk attribute of the Column object
     *
     * @return The Pk value
     */
    public boolean isPk() {
        return _isPk;
    }

    /**
     * Gets the Nullable attribute of the Column object
     *
     * @return The Nullable value
     */
    public  boolean isNullable() {
        return _isNullable;
    }

    /**
     * Gets the Indexed attribute of the DbColumn object
     *
     * @return The Indexed value
     */
    public  boolean isIndexed() {
        return _isIndexed;
    }

    /**
     * Gets the Unique attribute of the DbColumn object
     *
     * @return The Unique value
     */
    public boolean isUnique() {
        return _isUnique;
    }

    /**
     * Gets the DefaultValue attribute of the DbColumn object
     *
     * @return The DefaultValue value
     */
    public  String getDefaultValue() {
        return _defaultValue;
    }

    /**
     * 列的数据库备注
     * @return
     */
    public  String getRemarks() {
        return _remarks;
    }
    /**
     * Describe what the method does
     *
     * @return Describe the return value
     * @todo-javadoc Write javadocs for method
     * @todo-javadoc Write javadocs for return value
     */
    public int hashCode() {
        if(getTable() != null) {
            return (getTable().getSqlName() + "#" + getSqlName()).hashCode();
        }else {
            return (getSqlName()).hashCode();
        }
    }

    /**
     * Describe what the method does
     *
     * @param o
     *            Describe what the parameter does
     * @return Describe the return value
     * @todo-javadoc Write javadocs for method
     * @todo-javadoc Write javadocs for method parameter
     * @todo-javadoc Write javadocs for return value
     */
    public boolean equals(Object o) {
        if(this == o) return true;
        if(o instanceof Column) {
            Column other = (Column)o;
            if(getSqlName().equals(other.getSqlName())) {
                return true;
            }
        }
        return false;
    }

    /**
     * Describe what the method does
     *
     * @return Describe the return value
     * @todo-javadoc Write javadocs for method
     * @todo-javadoc Write javadocs for return value
     */
    public String toString() {
        return getSqlName();
    }

    public Object clone() {
        try {
            return super.clone();
        } catch (CloneNotSupportedException e) {
            //ignore
            return null;
        }
    }

    /**
     * 根据列名，根据sqlName计算得出，示例值： BirthDate
     **/
    public String getColumnName() {
        return columnName;
    }

    /**
     * 第一个字母小写的columName,等价于: StringHelper.uncapitalize(getColumnName()),示例值: birthDate
     **/
    public String getColumnNameFirstLower() {
        return StringKit.firstCharToLowerCase(getColumnName());
    }

    /**
     * 全部小写的columName,等价于: getColumnName().toLowerCase(),示例值: birthdate
     **/
    public String getColumnNameLowerCase() {
        return getColumnName().toLowerCase();
    }

    /**
     * 全部小写的columName,等价于: getColumnName().toLowerCase(),示例值: birthdate
     **/
    public String getColumnNameUpperCase() {
        return getColumnName().toUpperCase();
    }

    /**
     * 使用 getColumnNameFirstLower()替换
     * @deprecated use getColumnNameFirstLower() instead
     */
    public String getColumnNameLower() {
        return getColumnNameFirstLower();
    }

    /**
     * 得到 jdbcSqlType类型名称，示例值:VARCHAR,DECIMAL, 现Ibatis3使用该属性
     */
    public String getJdbcSqlTypeName() {
        return getJdbcType();
    }

    /**
     * 得到 jdbcSqlType类型名称，示例值:VARCHAR,DECIMAL, 现Ibatis3使用该属性
     */
    public String getJdbcType() {
        String result = JdbcType.getJdbcSqlTypeName(getSqlType());
        return result;
    }

    /**
     * 列的常量名称
     *
     * <br />
     * 示例值: BIRTH_DATE
     */
    public String getConstantName() {
        return StringKit.toUnderscoreName(getColumnName()).toUpperCase();
    }

    /**
     *
     * @deprecated
     */
    public boolean getIsNotIdOrVersionField() {
        return !isPk();
    }

    /** 列是否是String类型 */
    public boolean getIsStringColumn() {
        return DbDataTypesUtils.isString(getJavaType());
    }

    /** 列是否是日期类型 */
    public boolean getIsDateTimeColumn() {
        return DbDataTypesUtils.isDate(getJavaType());
    }

    /** 列是否是备用字段 */
    public boolean getIsRmColumn() {
        return getSqlName().startsWith("opt");
    }

    /** 列是否是操作日期 */
    public boolean getIsTimeStampColumn() {
        return DbDataTypesUtils.isTimeStamp(getJavaType());
    }

    /** 列是否是Number类型 */
    public boolean getIsNumberColumn() {
        return DbDataTypesUtils.isFloatNumber(getJavaType())
                || DbDataTypesUtils.isIntegerNumber(getJavaType());
    }

    /** 列是否是浮点数类型，是否含有小数点 */
    public boolean getIsFloatColumn() {
        return DbDataTypesUtils.isFloatNumber(getJavaType());
    }

    /** 检查是否包含某些关键字,关键字以逗号分隔 */
    public boolean contains(String keywords) {
        if(keywords == null) throw new IllegalArgumentException("'keywords' must be not null");
        return StringKit.contains(getSqlName(), keywords.split(","));
    }

    /**
     * 得到对应的javaType,如java.lang.String,
     * @return
     */
    public String getJavaType() {
        return javaType;
    }

    /**
     * 得到简短的javaType的名称，如com.company.model.UserInfo,将返回 UserInfo
     * @return
     */
    public String getSimpleJavaType() {
        return StringKit.getJavaClassSimpleName(getJavaType());
    }
    /**
     * 得到尽可能简短的javaType的名称，如果是java.lang.String,将返回String, 如com.company.model.UserInfo,将返回 com.company.model.UserInfo
     * @return
     */
    public String getPossibleShortJavaType() {
        if(getJavaType().startsWith("java.lang.")) {
            return getSimpleJavaType();
        }else {
            return getJavaType();
        }
    }

    public boolean isPrimitive() {
        return JavaTypeMapping.getWrapperTypeOrNull(getJavaType()) != null;
    }
    /**
     * 得到原生类型的javaType,如java.lang.Integer将返回int,而非原生类型,将直接返回getSimpleJavaType()
     * @return
     */
    public String getPrimitiveJavaType() {
        return JavaTypeMapping.getPrimitiveType(getSimpleJavaType());
    }


    /** nullValue for ibatis sqlmap: <result property="age" column="age" nullValue="0"  /> */
    public String getNullValue() {
        return JavaTypeMapping.getDefaultValue(getJavaType());
    }

    public boolean isHasNullValue() {
        return JavaTypeMapping.getWrapperTypeOrNull(getJavaType()) != null;
    }

    private void initOtherProperties() {
        javaType = DbDataTypesUtils.getPreferredJavaType(getSqlType(), getSize(), getDecimalDigits());
        columnName = StringKit.makeAllWordFirstLetterUpperCase(StringKit.toUnderscoreName(getSqlName()));
    }
    private String javaType;
    private String columnName;
}
